package com.neusoft.bizcore.activiti.service.impl;

import java.lang.reflect.Method;
import java.util.List;

import javax.persistence.EntityNotFoundException;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ApplicationObjectSupport;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import com.neusoft.bizcore.activiti.converter.PendingDataConverter;
import com.neusoft.bizcore.activiti.dto.PendingDataDTO;
import com.neusoft.bizcore.activiti.dto.ServiceDataModelDTO;
import com.neusoft.bizcore.activiti.enums.PendingDataStatusEnum;
import com.neusoft.bizcore.activiti.model.PendingData;
import com.neusoft.bizcore.activiti.repository.PendingDataRepository;
import com.neusoft.bizcore.activiti.service.PendingDataService;
import com.neusoft.bizcore.web.constant.ExceptionConstants;
import com.neusoft.bizcore.web.exception.UnitedException;
import com.neusoft.bizcore.web.support.Searchable;

import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class PendingDataServiceImpl extends ApplicationObjectSupport implements PendingDataService {

    @Autowired
    private PendingDataRepository pendingDataRepository;
    @Autowired
    private PendingDataConverter pendingDataConverter;

    @Override
    public List<PendingDataDTO> index(final Searchable searchable) {
        final List<PendingData> models = this.pendingDataRepository.index(searchable);
        return this.pendingDataConverter.toListDTO(models);
    }

    @Override
    public Page<PendingDataDTO> search(final Pageable pageable, final Searchable searchable) {
        final Page<PendingData> result = this.pendingDataRepository.search(pageable, searchable);
        final Page<PendingDataDTO> pageResult = this.pendingDataConverter.toPageDTO(result);
        return pageResult;
    }

    @Override
    public PendingDataDTO create(final PendingDataDTO dto) {
        final PendingData model = this.pendingDataConverter.toModel(dto);
        // 查询是否存在待保存数据，根据InstanceId和NodeId查询
        final List<PendingData> list = this.pendingDataRepository.findByInstanceIdAndNodeId(model);
        // 如果存在数据，全部删除
        if (CollectionUtils.isNotEmpty(list)) {
            this.pendingDataRepository.deleteAll(list);
        }
        // 保存业务流程信息
        this.pendingDataRepository.save(model);
        return this.pendingDataConverter.toDTO(model);
    }

    @Override
    public PendingDataDTO update(final Long id, final PendingDataDTO dto) {
        PendingData model;
        try {
            model = this.pendingDataRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }
        dto.setId(model.getId());
        this.pendingDataConverter.toModel(dto);
        this.pendingDataRepository.save(model);

        return this.pendingDataConverter.toDTO(model);
    }

    @Override
    public PendingDataDTO details(final Long id) {
        final PendingData model;
        try {
            model = this.pendingDataRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }

        final PendingDataDTO result = this.pendingDataConverter.toDTO(model);
        return result;
    }

    @Override
    public void delete(final Long id) {
        this.pendingDataRepository.deleteById(id);
    }

    @Override
    public List<PendingDataDTO> findByClazzName(final String clazzName) {
        final List<PendingData> models = this.pendingDataRepository.findByClazzName(clazzName);
        return this.pendingDataConverter.toListDTO(models);
    }

    @Override
    public PendingDataDTO updateStatus(final Long id, final PendingDataStatusEnum status) {
        PendingData model;
        try {
            model = this.pendingDataRepository.getOne(id);
        } catch (final EntityNotFoundException e) {
            throw new UnitedException(ExceptionConstants.ENTITY_NOT_FOUND, new Object[] {id });
        }
        model.setStatus(status);
        this.pendingDataRepository.save(model);

        return this.pendingDataConverter.toDTO(model);
    }

    @Override
    public List<PendingDataDTO> findByInstanceId(final String instanceId) {
        final List<PendingData> models = this.pendingDataRepository.findByInstanceId(instanceId);
        return this.pendingDataConverter.toListDTO(models);
    }

    @Override
    public void deleteByWorkNumAndNodeId(final String workNum, final String nodeId) {
        // 查询是否存在待保存数据，根据workNum和NodeId查询
        final List<PendingData> list = this.pendingDataRepository.findByWorkNumAndNodeId(workNum, nodeId);
        // 如果存在数据，全部删除
        if (CollectionUtils.isNotEmpty(list)) {
            this.pendingDataRepository.deleteAll(list);
        }
    }

    @Override
    public void deleteByWorkNum(final String workNum) {
        this.pendingDataRepository.deleteByWorkNum(workNum);
    }

    @Override
    public PendingDataDTO save(final String clazzName, final String methodName, final String workNum,
            final String taskId, final List<ServiceDataModelDTO> list) {
        if (StringUtils.isEmpty(clazzName)
                || StringUtils.isEmpty(methodName)
                || StringUtils.isEmpty(workNum)
                || StringUtils.isEmpty(taskId)
                || CollectionUtils.isEmpty(list)) {
            throw new UnitedException(ExceptionConstants.SAVE_PENDING_DATA_PARAMETER_NOT_VALIDATE,
                    new Object[] {clazzName },
                    new Object[] {methodName },
                    new Object[] {workNum },
                    new Object[] {taskId },
                    new Object[] {list });
        }

        final PendingDataDTO dto = new PendingDataDTO(clazzName, methodName, workNum, taskId, list);
        dto.setStatus(PendingDataStatusEnum.undeal);

        final PendingData model = this.pendingDataConverter.toModel(dto);
        // 查询是否存在待保存数据，根据InstanceId和NodeId查询
        final List<PendingData> listDatas = this.pendingDataRepository.findByInstanceIdAndNodeId(model);
        // 如果存在数据，全部删除
        if (CollectionUtils.isNotEmpty(list)) {
            this.pendingDataRepository.deleteAll(listDatas);
        }
        // 保存业务流程信息
        this.pendingDataRepository.save(model);
        return this.pendingDataConverter.toDTO(model);
    }

    @Override
    public List<PendingDataDTO> findByWorkNum(final String WorkNum) {
        final List<PendingData> models = this.pendingDataRepository.findByWorkNum(WorkNum);
        return this.pendingDataConverter.toListDTO(models);
    }

    @Override
    public String dealData(final String processInstanceId) {
        if (StringUtils.isEmpty(processInstanceId)) {
            return "Parameter 'processInstanceId' error. processInstanceId -> " + processInstanceId;
        }

        final List<PendingData> list = this.pendingDataRepository.findByInstanceId(processInstanceId);
        if (CollectionUtils.isNotEmpty(list)) {
            list.stream().forEach(item -> {
                try {
                    final Class<?> clazz = Class.forName(item.getClazzName());
                    final Method method = clazz.getMethod(item.getMethodName(), PendingDataDTO.class);
                    final Object obj = method.invoke(this.getApplicationContext().getBean(clazz),
                            this.pendingDataConverter.toDTO(item));
                    if (obj != null) {
                        PendingDataServiceImpl.log.info("result -> " + obj.toString());
                    }
                } catch (final Exception e) {
                    e.printStackTrace();
                }
            });
        } else {
            return "ERROR -> No data to process. ";
        }
        return "SUCCESS";
    }

}
